package com.zhuoyue.web.controller;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.zhuoyue.biz.core.api.dao.DeviceDao;
import com.zhuoyue.biz.core.api.dao.DeviceTypeMapper;
import com.zhuoyue.biz.core.api.domain.*;
import com.zhuoyue.biz.core.api.dto.rep.GroupDeviceRelationRep;
import com.zhuoyue.biz.core.api.dto.rep.TimedTaskReqDTO;
import com.zhuoyue.biz.core.api.dto.rep.ZigbeeDeviceRepDTO;
import com.zhuoyue.biz.core.api.dto.req.ZigbeeDeviceDTO;
import com.zhuoyue.biz.core.api.service.*;

import com.zhuoyue.biz.core.api.service.impl.DeviceService;
import com.zhuoyue.biz.core.api.service.impl.ProductInfoAppService;
import com.zhuoyue.biz.core.api.service.impl.WifiDeviceService;
import com.zhuoyue.biz.core.command.impl.intelligence.GroupCmd;
import com.zhuoyue.common.aop.auth.CheckLogin;
import com.zhuoyue.common.aop.auth.User;
import com.zhuoyue.common.constant.RedisKey;

import com.zhuoyue.common.group.ValidationGroups;
import com.zhuoyue.common.utils.JsonUtils;
import com.zhuoyue.common.utils.Time;
import com.zhuoyue.web.controller.aivoice.DuerosStatusReport;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.validator.constraints.Length;
import org.jetbrains.annotations.NotNull;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import com.zhuoyue.common.dto.ControllerResult;


import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.NotBlank;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


/**
 * 设备
 *
 * @author Administrator
 */
@RestController
@RequestMapping("/api/device")
@Validated
@Slf4j
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class AppZigbeeDeviceController {
    private final DeviceService deviceService;
    private final InfraredDeviceService infraredDeviceService;
    private final WifiDeviceService wifiDeviceService;
    private final DeviceTypeMapper deviceTypeMapper;
    private final ZigbeeDevicePropertyService zigbeeDevicePropertyService;
    private final RedisTemplate redisTemplate;
    private final StringRedisTemplate stringRedisTemplate;
    private final GroupService groupService;
    private final GroupDeviceRelationService groupDeviceRelationService;
    private final DeviceDao deviceDao;
    private final GatewayRedisService gatewayRedisService;
    private final RabbitTemplate rabbitTemplate;
    private final DeviceTaskService taskService;
    private final ProductInfoAppService productInfoAppService;

    @Value("${topic.rabbit.deviceRemoveGroup}")
    private String deviceRemoveGroup;

    /**
     * 一路面板
     */
    private static final String DEVICE_0FAA0504 = "0FAA0504";
    /**
     * 群组个数限制
     */
    private static final int GROUP_COUNT = 9;

    /**
     * @Description: zigbee设备添加
     * @param: zigbeeDeviceDTO
     * @return: com.zhuoyue.common.dto.ControllerResult
     * @author:wjming
     * @Date:2021/4/17 12:45
     */
    @PostMapping("/add")
    @CheckLogin
    public ControllerResult addDevice(@Validated(ValidationGroups.Insert.class) @RequestBody ZigbeeDeviceDTO zigbeeDeviceDTO, HttpServletRequest request) {
        User user = (User) request.getAttribute("user");
        log.info("request -> user:[{}_{}] [addDevice] -> [zigbeeDeviceDTO:{}]", user.getAccount(), user.getOrgCode(), com.alibaba.fastjson.JSONObject.toJSONString(zigbeeDeviceDTO));
        List<DeviceDO> deviceDos = deviceService.addDevice(zigbeeDeviceDTO);
        List<ZigbeeDeviceRepDTO> zigbeeDeviceRepDtoS = new ArrayList<>();
        deviceDos.stream().forEach(list -> {
            ZigbeeDeviceProperty zigbeeDeviceProperty = zigbeeDevicePropertyService.getById(list.getId());
            //查询产品功能信息
            List<String> functionList = productInfoAppService.getDeviceFun(list.getProdId());
            ZigbeeDeviceRepDTO zigbeeDeviceRepDTO = new ZigbeeDeviceRepDTO().deviceDoToDto(list, zigbeeDeviceProperty, null, functionList);
            zigbeeDeviceRepDtoS.add(zigbeeDeviceRepDTO);
        });
        log.info("result ->  [addDevice] -> [{}]", zigbeeDeviceRepDtoS);
        return ControllerResult.toReturnDataSuccess("设备添加成功", zigbeeDeviceRepDtoS);
    }

    /**
     * @Description: 根据设备ID修改Zigbee设备
     * @param: deviceId
     * @param: roomId
     * @param: name
     * @param: imgUrl
     * @param: pushType
     * @return: com.zhuoyue.common.dto.ControllerResult
     * @author:wjming
     * @Date:2021/4/17 13:45
     */
    @PutMapping("/modify")
    @CheckLogin
    public ControllerResult updateDevice(@Validated(ValidationGroups.Update.class) ZigbeeDeviceDTO dev) {
        DeviceDO device = new DeviceDO();
        device.setId(dev.getDeviceId());
        device.setRoomId(StringUtils.isNotEmpty(dev.getRoomId()) ? dev.getRoomId() : null);
        device.setName(StringUtils.isNotEmpty(dev.getName()) ? dev.getName() : null);
        device.setImgUrl(StringUtils.isNotEmpty(dev.getImgUrl()) ? dev.getImgUrl() : null);
        device.setPushType(StringUtils.isNotEmpty(dev.getPushType()) ? dev.getPushType() : null);
        device.setProdId(StringUtils.isNotEmpty(dev.getProdId()) ? dev.getProdId() : null);
        DeviceDO deviceDO = deviceService.myUpdateById(device);


        //设备属性发生变化时，通知小度
        //根据设备id查询设备的信息
        if (DEVICE_0FAA0504.equals(deviceDO.getOdIndex() + deviceDO.getDeviceType() + deviceDO.getProductType())) {
            DuerosStatusReport duerosStatusReport = new DuerosStatusReport();
            duerosStatusReport.duerosStatus(dev.getDeviceId());
        }
        //查询设备固定属性信息
        ZigbeeDeviceProperty zigbeeDeviceProperty = zigbeeDevicePropertyService.getById(dev.getDeviceId());
        //查询Action信息
        String actionJson = deviceService.getActionJson(deviceDO.getId());

        //查询产品功能信息
        List<String> functionList = productInfoAppService.getDeviceFun(deviceDO.getProdId());

        ZigbeeDeviceRepDTO zigbeeDeviceRepDTO = new ZigbeeDeviceRepDTO().deviceDoToDto(deviceDO, zigbeeDeviceProperty, actionJson, functionList);


        return ControllerResult.toReturnDataSuccess("修改成功", zigbeeDeviceRepDTO);
    }

    /**
     * @Description: 根据设备ID删除Zigbee设备
     * @param: deviceId
     * @param: request
     * @return: com.zhuoyue.common.dto.ControllerResult
     * @author:wjming
     * @Date:2021/4/17 13:45
     */
    @DeleteMapping("/delete")
    @CheckLogin
    public ControllerResult deleteDevice(@NotBlank(message = "设备ID不能为空") String deviceId, HttpServletRequest request) {

        User user = (User) request.getAttribute("user");
        if (user != null) {
            log.info("request -> user:[{}_{}] [deleteDevice] -> [deviceId:{}]",
                    user.getAccount(), user.getOrgCode(), deviceId);
        }
        deviceService.deleteDeviceById(deviceId);
        return ControllerResult.toReturnMessageSuccess("删除成功");
    }


    /**
     * 根据网关ID查询zigBee设备
     *
     * @param gatewayId 网关ID
     * @return
     */
    @GetMapping("/gateway/list")
    @CheckLogin
    public ControllerResult getGatewayDeviceList(@NotBlank(message = "网关ID不能为空") String gatewayId, HttpServletRequest request) {
        User user = (User) request.getAttribute("user");
        log.info("request -> user:[{}_{}] [getGatewayDeviceList] -> [gatewayId:{}]",
                user.getAccount(), user.getOrgCode(), gatewayId);
        List<ZigbeeDeviceRepDTO> deviceByGatewayId = deviceService.getDeviceByGatewayId(gatewayId);
        deviceByGatewayId.forEach(list -> {
            //查询设备固定属性信息
            ZigbeeDeviceProperty zigbeeDeviceProperty = zigbeeDevicePropertyService.getById(list.getId());
            if (zigbeeDeviceProperty != null) {
                list.setProperty(zigbeeDeviceProperty.getProperty());
            }
        });
        return ControllerResult.toReturnDataSuccess("获取成功", deviceByGatewayId);
    }


    /**
     * 修改房间ID
     *
     * @param
     * @return
     */
    @PutMapping(value = "/modifyRoomId")
    @CheckLogin
    public ControllerResult modifyHomeId(@NotNull("param不能为空！") String param) {

        JSONArray data = JSONArray.fromObject(param);
        List<InfraredDeviceDO> infraredDeviceDoS = new ArrayList<>();
        List<DeviceDO> deviceDoS = new ArrayList<>();
        List<WifiDevice> wifiDevices = new ArrayList<>();
        /**
         * 修改type区别设备类型，用户修改房间
         */
        for (int i = 0; i < data.size(); i++) {
            JSONObject dataObj = data.getJSONObject(i);
            long type = dataObj.getLong("type");
            if ("3".equals(type + "")) {
                InfraredDeviceDO infraredDeviceDo = new InfraredDeviceDO();
                infraredDeviceDo.setId(dataObj.getString("id"));
                infraredDeviceDo.setRoomId(dataObj.getString("roomId"));
                infraredDeviceDoS.add(infraredDeviceDo);

            } else if ("2".equals(type + "")) {
                WifiDevice wifiDevice = new WifiDevice();
                wifiDevice.setId(dataObj.getString("id"));
                wifiDevice.setRoomId(dataObj.getString("roomId"));
                wifiDevices.add(wifiDevice);
            } else {
                DeviceDO device = new DeviceDO();
                device.setId(dataObj.getString("id"));
                device.setRoomId(dataObj.getString("roomId"));
                deviceDoS.add(device);
            }

            boolean b = infraredDeviceService.updateBatchById(infraredDeviceDoS);
            boolean b1 = wifiDeviceService.updateBatchById(wifiDevices);
            boolean b2 = deviceService.updateBatchById(deviceDoS);
            if (!b && !b1 && !b2) {
                return ControllerResult.toParamFail("设备房间信息修改失败");
            }

        }
        return ControllerResult.toReturnMessageSuccess("房间修改成功");
    }


    /**
     * 添加设备类型
     *
     * @param
     * @return
     */
    @PostMapping(value = "/device/type")
    @CheckLogin
    public ControllerResult addDeviceType(@NotBlank(message = "设备类型不能为空") String deviceCode,
                                          String deviceKind, @NotBlank(message = "设备名称") String deviceName,
                                          String deviceType, @NotBlank(message = "图片地址") String img) {
        DeviceType build = DeviceType.builder().deviceCode(StringUtils.upperCase(deviceCode)).deviceKind(deviceKind).deviceName(deviceName)
                .deviceType(deviceType).img(img).build();
        deviceTypeMapper.insert(build);
        return ControllerResult.toReturnDataSuccess("添加成功", build);
    }


    /**
     * @Description: 添加设备固定属性值
     * @param: id
     * @param: deviceProperty
     * @return: com.zhuoyue.common.dto.ControllerResult
     * @author:wjming
     * @Date:2021/4/17 13:02
     */
    @PostMapping(value = "/device/property")
    @CheckLogin
    public ControllerResult devicePropertyAddOrModify(@NotBlank(message = "设备ID不能为空") String id,
                                                      @NotBlank(message = "设备属性不能为空") String deviceProperty, HttpServletRequest request) {
        User user = (User) request.getAttribute("user");
        log.info("request -> user:[{}_{}] [DevicePropertyAddOrModify] -> [id:{},deviceProperty:{}]", user.getAccount(), user.getOrgCode(), id, deviceProperty);
        DeviceDO deviceDO = deviceService.getById(id);
        Map<String, Object> map = JsonUtils.jsonToMap(deviceProperty);
        if (deviceDO == null) {
            return ControllerResult.toParamFail("设备不存在");
        }
        ZigbeeDeviceProperty zigbeeDeviceProperty = ZigbeeDeviceProperty.builder().property(deviceProperty).build();
        zigbeeDeviceProperty.setId(id);
        String type = deviceDO.getOdIndex() + deviceDO.getDeviceType() + deviceDO.getProductType();
        switch (type) {
            case "0FAA0B02":

                String duration = "duration";
                if (map.get(duration) == null) {
                    return ControllerResult.toParamFail("deviceProperty中的duration参数不能为空");
                }
                ZigbeeDeviceProperty property = zigbeeDevicePropertyService.getById(id);
                if (property != null) {
                    String property1 = property.getProperty();
                    JSONObject jsonObject = JSONObject.fromObject(property1);
                    jsonObject.putAll(map);
                    zigbeeDeviceProperty.setProperty(com.alibaba.fastjson.JSONObject.toJSONString(jsonObject));
                }
                break;
            case "0FAA8A11":
            case "0FAC0503":
                String acCode = "acCode";
                String brand = "brand";
                if (map.get(acCode) == null || map.get(brand) == null) {
                    return ControllerResult.toParamFail("参数错误");
                }
                zigbeeDeviceProperty.setProperty(deviceProperty);
                break;
            default:
                break;
        }

        try {
            zigbeeDevicePropertyService.saveOrUpdate(zigbeeDeviceProperty);
        } catch (Exception e) {
            return ControllerResult.toReturnMessageSuccess("请检查设备ID是否正确");
        }
        return ControllerResult.toReturnMessageSuccess("配置成功");
    }

    /**
     * 获取设备延时时间
     *
     * @param
     * @return
     */
    @GetMapping(value = "/delay/time")
    @CheckLogin
    public ControllerResult getDelayTime(@RequestParam @NotBlank(message = "设备类型不能为空") String deviceMac) {
        Object delayTime = redisTemplate.opsForValue().get(deviceMac.trim() + "_delayTime");
        if (delayTime == null) {
            return ControllerResult.toParamFail("设备延时时间不存在或已失效");
        } else {
            Map<String, Object> time = new HashMap<>(2);
            time.put("nowTime", Time.toLongMilli(LocalDateTime.now()));
            time.put("delayTime", delayTime);
            return ControllerResult.toReturnDataSuccess("查询成功", time);
        }

    }


    /**
     * 把单个设备配置到群组中
     * 设备配置到群组之中群组可以多个
     * 把设备配置到群组之中(可以添加到单个群组，也可以添加到多个群组)
     */
    @PostMapping(value = "/set/group")
    @CheckLogin
    public ControllerResult setDeviceGroup(@RequestParam @NotBlank(message = "设备类型不能为空") String deviceId,
                                           @RequestParam @NotBlank(message = "群组列表不能为空") String groupList) {
        List<String> groupIds = JSON.parseArray(groupList, String.class);
        //查询设备ID
        DeviceDO deviceDO = deviceDao.selectDeviceAndGatewayMac(deviceId);
        if (deviceDO == null) {
            return ControllerResult.toParamFail("设备信息不存在请检查设备信息");
        }

        if (GROUP_COUNT < groupIds.size()) {
            return ControllerResult.toParamFail("群组添加最多八个");
        }
        //持久化群组何设备之间的关系
        List<GroupDeviceRelation> groupDeviceRelations = new ArrayList<>(8);
        StringBuilder stringBuilder = new StringBuilder();
        List<Group> groups = groupService.listByIds(groupIds);
        if (CollectionUtils.isEmpty(groups)) {
            return ControllerResult.toParamFail("群组信息不存在,请刷新后重试。");
        }
        for (Group group : groups) {
            stringBuilder.append(group.getCode() + "00");
        }
        for (String group : groupIds) {
            GroupDeviceRelation groupDeviceRelation = new GroupDeviceRelation();
            groupDeviceRelation.setDeviceId(deviceId);
            groupDeviceRelation.setGroupId(group);
            groupDeviceRelations.add(groupDeviceRelation);
        }
        String randomCode = RandomStringUtils.randomNumeric(4);
        String cmd = GroupCmd.oneDeviceDeal(deviceDO.getGatewayMac(), deviceDO.getZigbeeMac(), stringBuilder.toString(), "07", randomCode);
        stringRedisTemplate.opsForValue().set(RedisKey.deviceAddMultipleGroup(deviceDO.getGatewayMac(), randomCode),
                JSON.toJSONString(groupDeviceRelations), 15, TimeUnit.SECONDS);
        gatewayRedisService.writeDataToGateway(deviceDO.getGatewayMac(), cmd);
        return ControllerResult.toReturnMessageSuccess("设备已配入到群组中");
    }

    /**
     * @Description: 获取当前设备群组列表信息
     * @param: deviceId
     * @param: homeId
     * @return: com.zhuoyue.common.dto.ControllerResult
     * @author:wjming
     * @Date:2021/4/17 13:46
     */
    @GetMapping(value = "/get/group/relation")
    @CheckLogin
    public ControllerResult getDeviceToGroupRelation(@RequestParam @NotBlank(message = "设备类型不能为空") String deviceId,
                                                     @RequestParam @NotBlank(message = "家庭ID不能为空") String homeId) {

        List<GroupDeviceRelation> groupDeviceRelations = groupDeviceRelationService.list(Wrappers.<GroupDeviceRelation>lambdaQuery()
                .eq(GroupDeviceRelation::getDeviceId, deviceId).orderByAsc(GroupDeviceRelation::getCreateTime));
        if (!CollectionUtils.isEmpty(groupDeviceRelations)) {
            List<String> idList = groupDeviceRelations.stream().map(groupRelation -> groupRelation.getId()).collect(Collectors.toList());

            List<Group> groups = groupService.listByIds(idList);
            List<GroupDeviceRelationRep> groupDeviceRelationReps = new ArrayList<>(8);
            groups.forEach(list -> {
                GroupDeviceRelationRep groupDeviceRelationRep = new GroupDeviceRelationRep();
                groupDeviceRelationRep.setGroupId(list.getId());
                groupDeviceRelationRep.setGroupName(list.getName() + (list.getHomeId().equals(homeId) ? "" : "(不是当前家庭)"));
                groupDeviceRelationReps.add(groupDeviceRelationRep);
            });
            return ControllerResult.toReturnDataSuccess("获取成功", groupDeviceRelationReps);
        } else {
            return ControllerResult.toParamFail("当前设备不存在群组关系");
        }

    }

    /**
     * 删除设备中所有的群组信息
     *
     * @param deviceId
     * @return
     */
    @DeleteMapping("/clear/all/group")
    @CheckLogin
    public ControllerResult getHomeById(String deviceId) {
        DeviceDO deviceDO = deviceDao.selectAllDeviceById(deviceId);
        if (deviceDO == null) {
            return ControllerResult.toParamFail("设备不存在");
        }
        Map<String, String> clearMap = new HashMap<>(2);
        clearMap.put("deviceMac", deviceDO.getZigbeeMac());
        clearMap.put("gatewayMac", deviceDO.getGatewayMac());
        rabbitTemplate.convertAndSend(deviceRemoveGroup, clearMap);
        return ControllerResult.toReturnMessageSuccess("正在发送请稍后");
    }

    @GetMapping("/timedTask/show")
    public ControllerResult getTimedTaskInformation(@RequestParam String zigbeeMac) {
        List<TimedTaskReqDTO> tasks = taskService.getTasksByZigbeeMac(zigbeeMac);

        return ControllerResult.toReturnDataSuccess("查询成功", tasks);
    }
}
